#pragma once

const int _son_process_nums = 4;

#include "task.hpp"
#include <functional>
#include <iostream>
#include <sys/types.h>
#include<sys/wait.h>
#include <unistd.h>
#include <string>
#include <vector>
#include <stdlib.h>
#include<time.h>
using func_t = std::function<void(int fd)>;

class tunnel
{
public:
    tunnel()
    {
    }
    tunnel(int wfd, std::string &name, pid_t id)
        : _wfd(wfd), _name(name), _son_id(id)
    {
    }
    ~tunnel()
    {
    }

    int Getwfd()
    {
        return _wfd;
    }
    std::string Getname()
    {
        return _name;
    }
    pid_t GetSonId()
    {
        return _son_id;
    }

    void Close()
    {
        close(_wfd);
    }

    void Wait()
    {
        pid_t rid = waitpid(_son_id,nullptr,0);
        if(rid > 0)
        {
            std::cout << "等待子进程成功:" << _son_id << std::endl;
        }
    }

private:
    int _wfd;
    std::string _name;
    pid_t _son_id;
};

class Process_pool
{
private:
    void Control(int& index)
    {
        sleep(3);
        index %= _tunnels.size();
        int x = rand() % tasks.size();
        write(_tunnels[index++].Getwfd(), &x, sizeof(x));
    }

public:
    Process_pool()
        : _num(_son_process_nums)
    {
        srand((unsigned int)time(nullptr));
    }

    Process_pool(int n)
        : _num(n)
    {
        srand((unsigned int)time(nullptr));
    }

    ~Process_pool()
    {
    }

    bool InitProcess_pool(func_t _task)
    {
        for (int i = 0; i < _num; i++)
        {
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            if (n < 0)
                return false;
            pid_t id = fork();
            if (id < 0)
                return false;

            if (id == 0)
            {
                for(auto& tunnel : _tunnels)
                {
                    tunnel.Close();
                }
                close(pipefd[1]);
                _task(pipefd[0]);

                exit(0);
            }

            close(pipefd[0]);
            std::string name = "tunnel_" + std::to_string(i);
            // std::cout << "-" << name << std::endl;
            //...
            _tunnels.push_back({pipefd[1], name, id});
        }

        return true;
    }

    void In_turn_ctrl()
    {
        int index = 0;
        while (1)
        {
            Control(index);
        }
    }

    void In_turn_ctrl(int count)
    {
        int index = 0;
        while (count)
        {
            Control(index);
            count--;
        }
    }

    void process_exit()
    {
        for(auto& tunnel : _tunnels)
        {
            tunnel.Close();
            tunnel.Wait();
        }
    }

private:
    std::vector<tunnel> _tunnels;
    int _num;
};